package com.wll.controller;

import com.wll.entity.Student;
import com.wll.mapper.StudentMapper;
import com.wll.utils.HanziUtil;
import org.apache.ibatis.session.ExecutorType;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.ArrayList;
import java.util.List;

/**
 * @ClassName: CardController.java
 * @author: wanglulu
 * @version: 1.0.0
 * @Description: 批量插入数据 （大数据添加）
 * @createTime: 2021/11/19 18:19
 * <p>
 * 参考地址
 * https://mp.weixin.qq.com/s/JodVMDCJVgR7gSsLUToihA
 * https://blog.csdn.net/chenping1993/article/details/106116000?spm=1001.2101.3001.6650.1&utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7ECTRLIST%7Edefault-1.no_search_link&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7ECTRLIST%7Edefault-1.no_search_link
 * <p>
 * 如果MyBatis需要进行批量插入，推荐使用 ExecutorType.BATCH 的插入方式，
 * 如果非要使用 <foreach>的插入的话，需要将每次插入的记录控制在 20~50 左右。
 *
 * 总结: 高 --> 低
 * sql插入的效率最高， xml foearch 插入效率次之, sqlsession batch type 第三， java for stream 循环插入 最低。
 *
 */
@RestController
@RequestMapping("batch/add/")
public class batchAddDataController {

    @Autowired
    StudentMapper studentMapper;

    @Autowired
    SqlSessionFactory sqlSessionFactory;

    /**
     * 请求api
     * GET http://localhost:8888/batch/add/xml/5000
     * <p>
     * xml foreach 批量插入  字段控制再 20以内 ，插入数量控制在 20-5条
     * 执行条数据  时间 ms
     * 1w        435
     * 3w        1240
     * 5w        1989
     *
     * @param num
     */
    @RequestMapping("xml/{num}")
    public void batchAddDataXml(@PathVariable("num") Integer num) {
        System.out.println("插入数量： " + num);
        if (num == null) {
            return;
        }
        //模拟前端 组装数据
        List<Student> studentList = getStudentList(num);
        long start = System.currentTimeMillis();
        // 调用接口添加数据
        studentMapper.batchData(studentList);
        long end = System.currentTimeMillis();
        System.out.println("执行时间：" + (end - start));
    }


    /**
     * 请求api
     * http://localhost:8888/batch/add/sql/5000
     *  sql 语句执行 批量插入
     * 执行条数据   时间 ms
     * 1w         273
     * 3w         505
     * 5w         481
     *
     * @param num
     */
    @RequestMapping("sql/{num}")
    public void batchAddData(@PathVariable("num") Integer num) {
        System.out.println("插入数量： " + num);
        long start = System.currentTimeMillis();
            List<Student> studentList = getStudentList(num);
            studentMapper.sqlInsert(studentList);
        long end = System.currentTimeMillis();
        System.out.println("执行时间：" + (end - start));
    }


    /**
     * sqlSession ExecutorType.BATCH 批量插入
     * 执行条数据   时间 ms
     * 1w         5682
     * 3w         17388
     * 5w         28362
     *
     * @param num
     */
    @RequestMapping("session/type/{num}")
    public void batchSessionTypeAddData(@PathVariable("num") Integer num) {
        System.out.println("插入数量： " + num);
        long start = System.currentTimeMillis();
        SqlSession session = sqlSessionFactory.openSession(ExecutorType.BATCH);
        try {
            List<Student> list = getStudentList(num);
            StudentMapper mapper = session.getMapper(StudentMapper.class);
            for (int i = 0; i < list.size(); i++) {
                mapper.insert(list.get(i));
                if (i%5000==4999) {
                    session.flushStatements();
                }
            }
            session.flushStatements();
        } finally {
            session.close();
        }
        long end = System.currentTimeMillis();
        System.out.println("执行时间：" + (end - start));
    }


    /**
     * java  for stream 批量插入  必要此方法进行批量插入  性能极差
     * 执行条数据   时间 ms
     * 1w         7493
     * 3w         22058
     * 5w         35686
     *
     * @param num
     */
    @RequestMapping("java/for/stream/{num}")
    public void batchForAddData(@PathVariable("num") Integer num) {
        System.out.println("插入数量： " + num);
        long start = System.currentTimeMillis();
        List<Student> list = getStudentList(num);
        list.stream().forEach(item -> {
            studentMapper.insert(item);
        });
        long end = System.currentTimeMillis();
        System.out.println("执行时间：" + (end - start));
    }


    /**
     * 组装数据
     *
     * @param num
     * @return
     */
    public static List<Student> getStudentList(Integer num) {
        List<Student> studentList = new ArrayList<>();
        if (num != null) {
            for (Integer i = 0; i < num; i++) {
                Student student = new Student();
                student.setName(HanziUtil.getRandomName());
                student.setAge(Math.round(20) * 100);
                student.setSex(num % 2 == 0 ? 1 : 0);
                student.setCid(1);
                student.setCardid(1);
                studentList.add(student);
            }
        }
        return studentList;
    }

}
